package com.kk;


import com.kk.utils.AdvanceThreadPool;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author MH
 * @date 2022-02-07
 * @description java 之 对lock、 synchronized 锁的了解
 */
public class GraspSynchronizedAndLock {
    private final static GraspSynchronizedAndLock GRASP_SYNCHRONIZED_AND_LOCK = new GraspSynchronizedAndLock();
    private final static GraspSynchronizedAndLock GRASP_SYNCHRONIZED_AND_LOCK1 = new GraspSynchronizedAndLock();
    private final Lock lock = new ReentrantLock();

    private int i = 0;
    private boolean isLocked = false;

    public static void main(String[] args) throws Exception {
        //无锁，1000个线程去操作共享资源i，最终i不为预期值。【】线程同步、加锁
        for (int i = 0; i < 1000; i++) {
            AdvanceThreadPool.poolExecutor.submit(GRASP_SYNCHRONIZED_AND_LOCK::addNum1);
        }

        //主线程等待 3秒执行，让线程把修改的值写进主内存
        TimeUnit.SECONDS.sleep(3);
        System.out.println(" final " + GRASP_SYNCHRONIZED_AND_LOCK.i);


        //自定义非可重入锁，死锁测试
        GRASP_SYNCHRONIZED_AND_LOCK1.dieLock();

    }


    /**
     * 1.无锁
     */
    public void addNumber0() {
            i++;
            System.out.println(i);
    }


    /**
     * 2.可重入锁，Lock手动上锁、解锁
     */
    public void addNumber() {
        lock.lock();
        try {
            i++;
            System.out.println(i);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //不解锁，其他的线程不会报异常 拿不到锁会一直等待
            lock.unlock();
        }
    }

    /**
     * 3.1.0 synchronized 锁代码块，自动锁
     */
    public void addNum1() {
        synchronized (Object.class) {
            i++;
            System.out.println(i);
        }
    }

    /**
     * 3.2.0 synchronized 锁方法，自动锁
     */
    public synchronized void addNum2() {
        i++;
        System.out.println(i);
    }


    /**
     * 自定义lock方法，测试不可重入锁
     *
     * @throws InterruptedException
     */
    public synchronized void lock() throws InterruptedException {
        while (isLocked) {
            System.out.println(this.getClass().getName()+" 已被锁住!");
            System.out.println("不可重入锁，进入死锁...");
            wait();
        }
        System.out.println(this.getClass().getName()+" 未上锁---");
        isLocked = true;
        // 线程第一次进入后就会将器设置为true，第二次进入是就会由于while true进入死循环
    }

    /**
     * 自定义unlock方法，测试不可重入锁
     */
    public synchronized void unlock() {
        // 将这个值设置为false目的是释放锁
        isLocked = false;
        // 结束阻塞
        notify();
    }

    /**
     * 测试不可重入锁,进入死锁
     */
    public void dieLock() throws InterruptedException {
        GRASP_SYNCHRONIZED_AND_LOCK1.lock();
        try {
            System.out.println("第一次上锁");
//            GRASP_SYNCHRONIZED_AND_LOCK1.unlock();
            dieLock2();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //不解锁，其他的线程不会报异常 拿不到锁会一直等待
            GRASP_SYNCHRONIZED_AND_LOCK1.unlock();
        }
    }

    /**
     * 测试不可重入锁
     */
    public void dieLock2() throws InterruptedException {
        GRASP_SYNCHRONIZED_AND_LOCK1.lock();
        try {
            System.out.println("第二次上锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //不解锁，其他的线程不会报异常 拿不到锁会一直等待
            GRASP_SYNCHRONIZED_AND_LOCK1.unlock();
        }
    }
}
